﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Infrastructure.Dispatcher
{
    /// <summary>
    /// 调度器基类
    /// </summary>
    public abstract class DispatcherBase : IDispatcher, IDisposable
    {
        #region Ctors

        public DispatcherBase()
        {
            this.Id = Guid.NewGuid().ToString();
            Status = StatusEnum.Stop;
            timer = null;
        }

        #endregion

        #region Fields

        /// <summary>
        /// 调度器状态
        /// </summary>
        StatusEnum Status;
        /// <summary>
        /// 定时器
        /// </summary>
        System.Timers.Timer timer;
        /// <summary>
        /// 是否已回收
        /// </summary>
        Boolean isDisposed;

        #endregion

        #region Protected Properties

        /// <summary>
        /// 定时器间隔
        /// 单位：毫秒
        /// </summary>
        protected abstract long Interval { get; }
        /// <summary>
        /// 是否立即执行
        /// </summary>
        protected abstract Boolean IsStartImmediate { get; }
        /// <summary>
        /// 是否忽略异常
        /// </summary>
        protected abstract Boolean IsIgnoreException { get; }

        #endregion

        #region IDispatcher Members

        /// <summary>
        /// 唯一标志id
        /// </summary>
        public string Id
        {
            get;
            private set;
        }

        /// <summary>
        /// 启动
        /// </summary>
        public void Start()
        {
            if (Status == StatusEnum.Stop) {
                Status = StatusEnum.Idle;
                timer = new Timer(Interval);
                timer.AutoReset = false;
                if (IsStartImmediate){
                    try
                    {
                        var ingTask = new Task(() =>
                        {
                            Status = StatusEnum.Running;
                            Dispatching();
                        });
                        var afterTask = ingTask.ContinueWith(t =>
                        {
                            Status = StatusEnum.Idle;
                            AfterDispatch();
                        });

                        var dispatcherTask = new DispatcherTask(ingTask, afterTask);
                        DispatcherBus.AddTask(dispatcherTask);
                        Status = StatusEnum.Pending;
                    }
                    catch (Exception ex) {
                        if (!IsIgnoreException) {
                            ProcessException(ex);
                        }
                    }
                }else {
                    timer.Elapsed += On_Dispatching;
                    timer.Start();
                }
            }
        }

        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            if (Status != StatusEnum.Stop) {
                Status = StatusEnum.Stop;
                if (timer != null) {
                    timer.Elapsed -= On_Dispatching;
                    timer.Stop();
                }
            }
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Pause()
        {
            if (timer != null) {
                timer.Elapsed -= On_Dispatching;
                timer.Stop();
            }           
        }
        /// <summary>
        /// 继续
        /// </summary>
        public void Continue()
        {
            timer.Elapsed += On_Dispatching;
            timer.Start();
        }

        #endregion

        #region Events

        void On_Dispatching(object sender, ElapsedEventArgs e)
        {
            try
            {
                var beforeTask = new Task(() =>
                {
                    BeforeDispatch();
                });
                var ingTask = beforeTask.ContinueWith(t =>
                {
                    Status = StatusEnum.Running;
                    Dispatching();
                });
                var afterTask = ingTask.ContinueWith(t =>
                {
                    Status = StatusEnum.Idle;
                    AfterDispatch();
                });
                var dispatcherTask = new DispatcherTask(beforeTask, ingTask, afterTask);
                DispatcherBus.AddTask(dispatcherTask);
                Status = StatusEnum.Pending;
            }
            catch (Exception ex) {
                if (!IsIgnoreException)
                {
                    ProcessException(ex);
                }
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
        }

        ~DispatcherBase() {
            Dispose(false);
        }

        void Dispose(Boolean disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    if (timer != null)
                    {
                        Status = StatusEnum.Stop;
                        timer.Elapsed -= On_Dispatching;
                        timer.Dispose();
                    }
                    //通知公共语言时，不要再调用对象的终结器，避免重复调用
                    GC.SuppressFinalize(this);
                }
                isDisposed = true;
            }
        }

        #endregion

        #region Override

        /// <summary>
        /// 调度前
        /// </summary>
        void BeforeDispatch() {
            if (timer != null)
            {
                timer.Elapsed -= On_Dispatching;
                timer.Stop();
            }
        }
        /// <summary>
        /// 调度
        /// 子类重写
        /// </summary>
        public abstract void Dispatching();
        /// <summary>
        /// 调度后
        /// </summary>
        void AfterDispatch() {
            if (timer != null) {
                timer.Elapsed += On_Dispatching;
                timer.Start();
            }            
        }

        /// <summary>
        /// 处理异常
        /// </summary>
        void ProcessException(Exception ex) { 
            
        }

        #endregion

    }
}
